#pragma once
#include "PublicHead.h"
#include "io_service_pool.h"

class client_holder;

class client_session :
	public boost::enable_shared_from_this<client_session>
{
public:
	client_session(
		INetNotify* pNetNotify, 
		CLogModule* pLogModule, 
		boost::asio::io_service& io_service_,
		client_holder& client_holder_,
		NetIDGenerator& net_id_
		);

	virtual ~client_session( void );
	virtual void Start( void );
	virtual void Close( void );
	virtual void SendData( const char* pData, unsigned int unDataLength );
	virtual unsigned __int64 GetClientID( void ) { return m_ullClientID; };

	boost::asio::ip::tcp::socket& get_socket( void ) { return m_socket_; };

private:
	void handle_read(const boost::system::error_code& error,const size_t bytes_transferred);
	void handle_write(const boost::system::error_code& error,const size_t bytes_transferred);
	void handle_close( void );

private:
	INetNotify* m_pNetNotify;
	CLogModule* m_pLogModule;
	client_holder& m_client_holder;
	boost::asio::ip::tcp::socket m_socket_;
	boost::asio::io_service& m_io_service_;
	boost::array<char, 1024> data_; 
	NetIDGenerator& m_NetIDGenerator;
	unsigned __int64 m_ullClientID;
};

typedef boost::shared_ptr<client_session> client_session_ptr;
typedef std::map<unsigned __int64,client_session_ptr> MAP_CLIENT;

class client_holder
{
public:
	void join(client_session_ptr client_ptr)
	{
		boost::mutex::scoped_lock lock(m_mux);
		m_mapClient.insert( std::pair<unsigned __int64,client_session_ptr>(client_ptr->GetClientID(),client_ptr) );
	}

	void leave(unsigned __int64 clientid)
	{
		boost::mutex::scoped_lock lock(m_mux);
 		MAP_CLIENT::iterator it = m_mapClient.find(clientid);
 		if (it != m_mapClient.end()) m_mapClient.erase(it);
	}

	client_session_ptr get_client(unsigned __int64 clientid)
	{
 		MAP_CLIENT::iterator it = m_mapClient.find(clientid);
 		if (it != m_mapClient.end())
 			return it->second;
		return client_session_ptr();
	}

	void stop_all( void )
	{
		boost::mutex::scoped_lock lock(m_mux);
		for (MAP_CLIENT::iterator it = m_mapClient.begin();it != m_mapClient.end();it++)
		{
			it->second->Close();
		}
	}

private:
	MAP_CLIENT m_mapClient;
	boost::mutex m_mux;
};

class CNetServer :
	public INetServer
{
public:
	CNetServer(
		INetNotify* pNetNotify, 
		CLogModule* pLogModule, 
		boost::shared_ptr<io_service_pool> io_service_pool,
		NetIDGenerator& net_id_
		);
	virtual ~CNetServer(void);

	virtual void SetServerPort( unsigned short nPort );
	virtual void Start_Service( void );
	virtual void Stop_Service( void );
	virtual void CloseClient( unsigned __int64 nClientID );
	virtual void KickAllClient( void );
	virtual void SendData( unsigned __int64 nClientID, const char* pData, unsigned int unDataLength );

private:
	boost::shared_ptr<boost::asio::ip::tcp::acceptor> m_acceptor_ptr;
	boost::shared_ptr<io_service_pool> m_io_service_pool_ptr;
	client_holder m_client_hodler;
	INetNotify* m_pNetNotify;
	CLogModule* m_pLogModule;
	boost::array<char, 1024> data_; 
	NetIDGenerator& m_NetIDGenerator;

private:
	void handle_accept(client_session_ptr new_client,const boost::system::error_code& error);
};
